//由于ntifs.h对ntddk.h和wdm.h的包含关系，测试文件不能包含wdm.h或ntddk.h，否则报错

/*
 * 版权所有 (c) 纳特通信有限公司 2022-2022
 * 功能说明   :  GT device and configuration interface
 * 创建日期   : 2022年05月13日
 */
#ifndef __CFGT_H__
#define __CFGT_H__


#include "nlslb_uapi.h"
#include "wlan_spec.h"
#include "wlan_types.h"

#include<intrin.h>
#include<ndis.h>
#include<stdint.h>
#include<ntifs.h>

#include"oal_types.h"

#include"oal_util.h"
#include "gf61 wlan_spec_gf61.h"

#ifdef PRE_GT_DEBUG
 ///////////////////////////或许将str换成wdm中的string函数//////////////////////////
#define __FILE_NAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
///////////////////////////////////////////////////////////////////////////////////
#define DBG(fmt, ...) DbgPrint(KERN_DEBUG "[%s:%d]"fmt, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
#define ERR(fmt, ...) DbgPrint(KERN_ERR "[%s:%d]"fmt, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#define ERR(fmt, ...)
#endif

#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif // !ETH_LEN

#define CFGT_PSK_MAX_LEN 6
//typedef unsigned long size_t;

struct cfgt_ap_settings {
    int beacon_interval;
    int channel;
    uint8_t bandwidth;
    const uint8_t* ssid;
    unsigned long ssid_len;
    //size_t ssid_len;
    uint8_t symbol_type_index;
    uint8_t cell_id;
    uint8_t cp;
    uint8_t sysmsg_period;
    uint8_t s_cfg_idx;
    uint8_t cc_start_pos;
    uint8_t psk[CFGT_PSK_MAX_LEN];
};

struct cfgt_sta_settings {
    int scan_interval;
    int channel;
    uint8_t bandwidth;
    uint8_t symbol_type_index;
    uint8_t cell_id;
    uint8_t psk[CFGT_PSK_MAX_LEN];
};

struct cfgt_vap_settings {
    uint8_t iftype; // 参考wlan_vap_mode_enum
    union {
        struct cfgt_ap_settings ap_settings;
        struct cfgt_sta_settings sta_settings;
    };
};

struct gt_vif_params {
    uint32_t flags;
    uint8_t macaddr[ETH_ALEN];
};

struct gt_key_params {
    const uint8_t* key;
    const uint8_t* seq;
    int key_len;
    int seq_len;
    uint16_t vlan_id;
    uint32_t cipher;
    enum nlgt_key_mode mode;
};

struct gt_station_parameters {
    int todo;
};

struct gt_station_del_parameters {
    const uint8_t* mac;
    uint8_t subtype;
    uint16_t reason_code;
};

struct gt_station_info {
    const uint8_t* assoc_req_ies;
    //size_t assoc_req_ies_len;
    unsigned long assoc_req_ies_len;
};
struct gtphy;

struct cfgt_scan_request {
    int todo;
};

#pragma pack(1)
typedef struct {
    char ssid[GT_MAX_SSID_LEN];
    char bssid[WLAN_MAC_ADDR_LEN];
    uint32_t flag;
    int  channel;
    int  bandwidth;
    int  symbol_type_idx;
    int vendor_ie_len;
    char vendor_ie[GT_MAX_VENDOR_IE_LEN];
} cfgt_scan_result_item_stru;

#define MAX_RESULT_ITEM GT_MAX_SCAN_RESULT_NUM
#pragma pack(1)
struct cfgt_scan_result {
    int count;
    cfgt_scan_result_item_stru items[MAX_RESULT_ITEM];
};

typedef enum {
    DRIVER_EVENT_ASSOC = 0,
    DRIVER_EVENT_DISASSOC,
    DRIVER_EVENT_SCAN_RESULT,
    DRIVER_EVENT_CONNECT_RESULT,
    DRIVER_EVENT_MGMT_RX,
    DRIVER_EVENT_DEV_STATE_CHANGE,

    DRIVER_EVENT_CNT
} driver_event_enum;

#pragma pack(1)
struct cfgt_rpt_event_hdr {
    uint32_t type; // driver_event_enum
    uint32_t len; // value length
    uint8_t* value;
};

typedef struct {
    struct cfgt_rpt_event_hdr hdr;
    uint8_t state;
} cfgt_dev_state_change_event;

typedef struct {
    struct cfgt_rpt_event_hdr hdr;
    uint8_t addr[WLAN_MAC_ADDR_LEN];
}cfgt_disassoc_rpt_event;

struct cfgt_scan_result_rpt_event {
    struct cfgt_rpt_event_hdr hdr;
    struct cfgt_scan_result result;
};

struct cfgt_connect_result {
    int result; // 0: succ 1: fail
    int reason;
    uint8_t addr[WLAN_MAC_ADDR_LEN];
};

#pragma pack(1)
struct cfgt_connect_result_rpt_event {
    struct cfgt_rpt_event_hdr hdr;
    struct cfgt_connect_result result;
};

struct cfgt_connect_params {
    uint32_t ifindex;
    char bssid[WLAN_MAC_ADDR_LEN];
};

struct gt_channel {
    uint32_t center_freq;
    uint16_t freq_offset;
};

struct gt_survey_info {
    struct gt_channel* channel;
    uint64_t time;
    uint64_t time_busy;
    uint64_t time_ext_busy;
    uint64_t time_rx;
    uint64_t time_tx;
    uint64_t time_scan;
    uint64_t time_bss_rx;
    uint32_t filled;
    int8_t noise;
};

struct cfgt_mgmt_tx_params {
    int todo;
};

#define GT_MAX_VENDOR_PKT_LEN 256
#pragma pack(1)
typedef struct {
    struct cfgt_rpt_event_hdr hdr;
    uint8_t data[GT_MAX_VENDOR_PKT_LEN];
} cfgt_mgmt_rx_rpt_event;

/**
 * enum gtphy_params_flags - set_gtphy_params bitfield values
 * @GTPHY_PARAM_SYMBOL_TYPE: gtphy->symbol_type has changed
 */
enum gtphy_params_flags {
    GTPHY_PARAM_SYMBOL_TYPE = 1 << 0,
};
////////////////////////////////////////////////////////////////////
//net_device换成ndis下的ndis设备类结构体
////////////////////////////////////////////////////////////////////

struct cfgt_ops {
    int	(*start_vap)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        struct cfgt_vap_settings* settings);
    int	(*stop_vap)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev);
    int	(*config_vap)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        struct cfgt_vap_settings* settings);
    int	(*set_gtphy_params)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        uint32_t changed);
    int	(*add_key)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* netdev,
        uint8_t key_index, BOOL pairwise, const uint8_t* mac_addr,
        struct gt_key_params* params);
    int	(*get_key)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* netdev,
        uint8_t key_index, BOOL pairwise, const uint8_t* mac_addr,
        void* cookie,
        void (*callback)(void* cookie, struct gt_key_params*));
    int	(*del_key)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* netdev,
        uint8_t key_index, BOOL pairwise, const uint8_t* mac_addr);

    int	(*set_default_key)(struct gtphy* gtphy,
        struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* netdev,
        uint8_t key_index, BOOL unicast, BOOL multicast);

    int	(*add_station)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        const uint8_t* mac,
        struct gt_station_parameters* params);
    int	(*del_station)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        struct gt_station_del_parameters* params);
    int	(*change_station)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        const uint8_t* mac,
        struct gt_station_parameters* params);
    int	(*get_station)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        const uint8_t* mac, struct gt_station_info* sinfo);
    int	(*dump_station)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        int idx, uint8_t* mac, struct gt_station_info* sinfo);

    int	(*scan)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        struct cfgt_scan_request* request);
    int	(*connect)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        struct cfgt_connect_params* sme);
    int	(*disconnect)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev,
        uint16_t reason_code);

//#ifdef CONFIG_CFGT_TESTMODE
//    int	(*testmode_cmd)(struct gtphy* gtphy, struct gt_dev* gdev,
//        void* data, int len);
//    int	(*testmode_dump)(struct gtphy* gtphy, struct sk_buff* skb,
//        struct netlink_callback* cb,
//        void* data, int len);
//#endif

    int	(*dump_survey)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* netdev,
        int idx, struct gt_survey_info* info);
    int (*enable_vendor_ie)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev, const uint8_t* data, int len);
    int (*disable_vendor_ie)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev);
    int (*mgmt_tx)(struct gtphy* gtphy, struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev, const uint8_t* data, int len);
};

struct gt_mac_address {
    uint8_t addr[ETH_ALEN];
};

enum gtphy_flags {
    /* use hole at 0 */
    /* use hole at 1 */
    /* use hole at 2 */
    GTPHY_FLAG_NETNS_OK = BIT(3),
    GTPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
    GTPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
    /* use hole at 11 */
    /* use hole at 12 */
    GTPHY_FLAG_HAVE_AP_SME = BIT(17),
    GTPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23),
};
///////////////////////哈希表,wdm中未找到hash list 定义////////////////////////
struct hlist_node {
    struct hlist_node* next;
    struct hlist_node** pprev;
};

struct hlist_head {
    struct hlist_node* first;
};
/// struct net//////////////////////////////////////
//typedef struct NET_BUFFER net;
//typedef struct net* possible_net_t;


struct gtphy {
    struct _FAST_MUTEX mtx;

    /* Supported interface modes, OR together BIT(NLGT_IFTYPE_...) */
    uint16_t interface_modes;

    uint32_t flags, features;

    const void* privid;

    struct _DEVICE_OBJECT dev;

    BOOL registered;

    struct NET_BUFFER* _net;

    uint8_t symbol_type;

    __declspec(align(32)) char priv[]; 	//__attribute__((aligned(NETDEV_ALIGN)));
};

#define inline __forceinline

static inline void write_pnet(struct NET_BUFFER** pnet, struct NET_BUFFER* net_para)
{
    *pnet = net_para;
}

static inline struct NET_BUFFER* read_pnet(struct NET_BUFFER* const* pnet)
{
    return *pnet;
}

static inline struct NET_BUFFER* gtphy_net(struct gtphy* gtphy)
{
    return read_pnet(&gtphy->_net);
}

static inline void gtphy_net_set(struct gtphy* gtphy, struct NET_BUFFER* net_para)
{
    write_pnet(&gtphy->_net, net_para);
}

/**
 * gtphy_priv - return priv from gtphy
 *
 * @gtphy: the gtphy whose priv pointer to return
 * Return: The priv of @gtphy.
 */
//#define WDM_BUG_ON(condition) do{\
//    if(__assume(!(condition))){\
//        KeBugCheckEx(BUGCODE_WDM_DRIVER, 0, 1, 2, 3);\
//    } } while (0)

#define WDM_BUG_ON(condition) if(condition) {\
DbgBreakPoint();\
}

static inline void* gtphy_priv(struct gtphy* gtphy)
{
    WDM_BUG_ON(!gtphy);
    return &gtphy->priv;
}

/**
 * gtphy_name - get gtphy name
 *
 * @gtphy: The gtphy whose name to return
 * Return: The name of @gtphy.
 */
static inline UNICODE_STRING gtphy_name(struct gtphy* gtphy)
{
    POBJECT_NAME_INFORMATION device_name;

    ULONG BufferSize = 256;
    PULONG returnLength;

    device_name = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, BufferSize, 'name');
    returnLength= (PULONG)ExAllocatePoolWithTag(NonPagedPool, BufferSize, 'nlen');

    ObQueryNameString(&gtphy->dev, device_name, BufferSize, returnLength);

    ExFreePool(returnLength);
    return device_name->Name;
    //return dev_name(&gtphy->dev);//获取设备（驱动）名
}

/**
 * gtphy_new_nm - create a new gtphy for use with cfgt
 *
 * @ops: The configuration operations for this device
 * @sizeof_priv: The size of the private area to allocate
 * @requested_name: Request a particular name.
 *	NULL is valid value, and means use the default phy%d naming.
 *
 * Create a new gtphy and associate the given operations with it.
 * @sizeof_priv bytes are allocated for private use.
 *
 * Return: A pointer to the new gtphy.
 */

 ///////////////////这是一个core.c中的接口，等到core.c中再改/////////////////////////
struct gtphy* gtphy_new_nm(const struct cfgt_ops* ops, int sizeof_priv,
    const char* requested_name);
////////////////////////////////////////////////////////////////////////////////////

/**
 * gtphy_new - create a new gtphy for use with cfgt
 *
 * @ops: The configuration operations for this device
 * @sizeof_priv: The size of the private area to allocate
 *
 * Create a new gtphy and associate the given operations with it.
 * @sizeof_priv bytes are allocated for private use.
 *
 * Return: A pointer to the new gtphy.
 */
static inline struct gtphy* gtphy_new(const struct cfgt_ops* ops,
    int sizeof_priv)
{
    return gtphy_new_nm(ops, sizeof_priv, NULL);
}

/**
 * gtphy_register - register a gtphy with cfgt
 *
 * @gtphy: The gtphy to register.
 *
 * Return: A non-negative gtphy index or a negative error code.
 */

 /////////////////////////同上////////////////////////////////////
int gtphy_register(struct gtphy* gtphy);
////////////////////////////////////////////////////////////////

#define ASSERT_GTPHY_LOCK(gtphy) ExIsResourceAcquiredLite(&(gtphy)->mtx)

/**
 * gtphy_unregister - deregister a gtphy from cfgt
 *
 * @gtphy: The gtphy to unregister.
 *
 * After this call, no more requests can be made with this priv
 * pointer, but the call may sleep to wait for an outstanding
 * request that is being handled.
 */

 ///////////////////////////接口//////////////////////////////////
void gtphy_unregister(struct gtphy* gtphy);
////////////////////////////////////////////////////////////////

/**
 * gtphy_free - free gtphy
 *
 * @gtphy: The gtphy to free
 */
void gtphy_free(struct gtphy* gtphy);

/**
 * gtphy_lock - lock the gtphy
 * @gtphy: the gtphy to lock
 *
 * This is mostly exposed so it can be done around registering and
 * unregistering netdevs that aren't created through cfgt calls,
 * since that requires locking in cfgt when the notifiers is
 * called, but that cannot differentiate which way it's called.
 *
 * When cfgt ops are called, the gtphy is already locked.
 */

 //////线程锁的获取与释放操作////////////////////////////////
static inline void gtphy_lock(struct gtphy* gtphy)
//__acquires(&gtphy->mtx)
{
    //mutex_lock(&gtphy->mtx);

    ExInitializeFastMutex(&gtphy->mtx);
    ExAcquireFastMutex(&gtphy->mtx);
    _WriteBarrier();//__acquire(&gtphy->mtx);
}

/**
 * gtphy_unlock - unlock the gtphy again
 * @gtphy: the gtphy to unlock
 */
static inline void gtphy_unlock(struct gtphy* gtphy)
//__releases(&gtphy->mtx)
{
    //__release(&gtphy->mtx);
    //mutex_unlock(&gtphy->mtx);
    _WriteBarrier();
    ExReleaseFastMutex(&gtphy->mtx);
}
/////////////////////////////////////////////////////

/**
 * cfgt_new_sta - notify userspace about station
 *
 * @dev: the netdev
 * @mac_addr: the station's address
 * @sinfo: the station information
 * @gfp: allocation flags
 */
void cfgt_new_sta(struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev, const uint8_t* mac_addr,
    struct gt_station_info* sinfo, POOL_TYPE gfp);

/**
 * cfgt_disconnected - notify cfgt that connection was dropped
 *
 */
void cfgt_disconnected(struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev, uint16_t reason,
    const uint8_t* ie, size_t ie_len,
    BOOL locally_generated, POOL_TYPE gfp);
/**
 * cfgt_register_dev_gtphy_map - add map between _NDIS_DEVICE_OBJECT_ATTRIBUTES and gtphy
 */
int cfgt_register_dev_gtphy_map(struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev, struct gtphy* gtphy);
int cfgt_unregister_dev_gtphy_map(struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev);
struct gtphy* cfgt_get_gtphy_from_netdev(struct _NDIS_DEVICE_OBJECT_ATTRIBUTES* dev);

#ifndef CONFIG_CFGT_STANDALONE
extern int cfgt_init(void);
extern void cfgt_exit(void);
#endif
#endif
